home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / Folder Watching / FW Receiver ƒ / Sources / AppleEvents.c next >
Encoding:
Text File  |  1996-02-16  |  16.3 KB  |  658 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        AppleEvents.c
  3.     
  4.     Contains:    The main routine
  5.     
  6.     Written by:    Chris White, Developer Technical Support
  7.     
  8.     Copyright:    © 1995 by Apple Computer, Inc., all rights reserved.
  9.     
  10.     Change History (most recent first):
  11.     
  12.             26/01/96            GS        FW Receiver
  13.                                         Added ability to accept and act on Apple events from
  14.                                         Folder Watcher FBA application.
  15.  
  16.             12/18/95            CW        First release
  17.  
  18. */
  19.  
  20. // System Includes
  21.  
  22. #ifndef __APPLEEVENTS__
  23.     #include <AppleEvents.h>
  24. #endif
  25.  
  26. #include <ASRegistry.h>
  27. #include <Notification.h>
  28. #include <Icons.h>
  29. #include <Resources.h>
  30. #ifndef __SOUND__
  31.     #include <Sound.h>
  32. #endif
  33. #include <TextUtils.h>
  34.  
  35.  
  36.  
  37.  
  38. // Application includes
  39.  
  40. #ifndef __BAREBONES__
  41.     #include "BareBones.h"
  42. #endif
  43.  
  44. #ifndef __PROTOTYPES__
  45.     #include "Prototypes.h"
  46. #endif
  47.  
  48. #include <Resources.h>
  49.  
  50.  
  51. typedef struct MyNotificationRecord
  52. {
  53.     NMRec   notification;
  54.     Str255  notificationString;
  55. } MyNotificationRecord, *MyNotificationPtr;
  56.  
  57.  
  58.                 // The events sent by the Folder Watcher FBA
  59. #define    kFolderWatcherSuite        'wFWS'
  60.  
  61. enum
  62. {
  63.     kTypeFileAdded = 'wTFA', kTypeFileRemoved = 'wTFR', kTypeFileModified = 'wTFC'
  64. };
  65.  
  66.  
  67. const short        ChangeSTRs = 200;
  68. enum
  69. {
  70.     kAddedStr = 1, kRemovedStr, kModifiedStr
  71. };
  72.  
  73. const short        SubroutineSTRs = 300;
  74. enum
  75. {
  76.     kAddedSub = 1, kRemovedSub, kModifiedSub
  77. };
  78.  
  79. const short        NotificationIcon = 501;
  80.  
  81.     // Prototypes
  82. pascal OSErr HandleOpenApplication( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon );
  83. pascal OSErr HandleQuitApplication( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon );
  84. pascal OSErr HandleOpenDocuments( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon );
  85. pascal OSErr HandlePrintDocuments( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon );
  86.  
  87. pascal OSErr HandleFileAdded( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon );
  88. pascal OSErr HandleFileRemoved( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon );
  89. pascal OSErr HandleFileModified( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon );
  90.  
  91. pascal OSErr HandleASSubroutine( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon );
  92.  
  93. void        DisplayChange( AEDesc* theDesc, short theChange );
  94. void        DisplayChangeDesc( AEDesc* theDesc, short theChange );
  95. void        AppendPStr( StringPtr sourceStr, StringPtr destStr );
  96. OSErr        GetDescriptorData( const AEDesc* theDesc, Ptr destPtr, Size maxSize );
  97. OSErr        FSSpecIsDirectory( FSSpec* theSpec, Boolean* theResult );
  98. OSErr        GetParentDirectoryName( FSSpec* theSpec, StringPtr theName );
  99.  
  100. void        InitNotification( void );
  101. OSErr        Notify( Boolean fSound, short iconID, StringPtr message );
  102. OSErr        InstallNotification( Boolean fSound, short iconID, StringPtr message );
  103. OSErr        RemoveNotification( void );
  104.  
  105. short        PositiveRandom( void );
  106.  
  107.  
  108.     // Globals
  109. Str255                gAddedSubroutineName;
  110. Str255                gRemovedSubroutineName;
  111. Str255                gModifiedSubroutineName;
  112.  
  113. NMUPP                gMyNMProcPtr = NULL;
  114. Boolean                gRemoveNotification;
  115. MyNotificationPtr    gNotificationPtr;
  116. short                gNumberSounds;
  117. SndChannelPtr        gSoundChannel;
  118.  
  119. #pragma segment Initialize
  120.  
  121. OSErr InstallAppleEventHandlers ( void )
  122. {
  123.     short err;
  124.     
  125.     InitNotification( );
  126.  
  127.     gAddedSubroutineName[0] = 0;
  128.     gRemovedSubroutineName[0] = 0;
  129.     gModifiedSubroutineName[0] = 0;
  130.     
  131.     err = AEInstallEventHandler ( kCoreEventClass, kAEOpenApplication,
  132.                         NewAEEventHandlerProc( HandleOpenApplication ), 0L, false );
  133.     if (noErr != err) goto done;
  134.  
  135.     err = AEInstallEventHandler ( kCoreEventClass, kAEQuitApplication,
  136.                         NewAEEventHandlerProc( HandleQuitApplication ), 0L, false );
  137.     if (noErr != err) goto done;
  138.  
  139.     err = AEInstallEventHandler ( kCoreEventClass, kAEOpenDocuments,
  140.                         NewAEEventHandlerProc (HandleOpenDocuments ), 0L, false );
  141.     if (noErr != err) goto done;
  142.  
  143.     err = AEInstallEventHandler ( kCoreEventClass, kAEPrintDocuments,
  144.                         NewAEEventHandlerProc( HandlePrintDocuments ), 0L, false );
  145.     if (noErr != err) goto done;
  146.                         
  147.                         // Events from Folder Watcher FBA
  148.                         
  149.     err = AEInstallEventHandler ( kFolderWatcherSuite, kTypeFileAdded,
  150.                         NewAEEventHandlerProc( HandleFileAdded ), 0L, false );
  151.     if (noErr != err) goto done;
  152.                         
  153.     err = AEInstallEventHandler ( kFolderWatcherSuite, kTypeFileRemoved,
  154.                         NewAEEventHandlerProc( HandleFileRemoved ), 0L, false );
  155.     if (noErr != err) goto done;
  156.                         
  157.     err = AEInstallEventHandler ( kFolderWatcherSuite, kTypeFileModified,
  158.                         NewAEEventHandlerProc( HandleFileModified ), 0L, false );
  159.     if (noErr != err) goto done;
  160.     
  161.                         // Events from Script Application
  162.  
  163.     err = AEInstallEventHandler ( kASAppleScriptSuite, kASSubroutineEvent,
  164.                         NewAEEventHandlerProc( HandleASSubroutine ), 0L, false );
  165.     if (noErr != err) goto done;
  166.  
  167. done:        
  168.     return err;
  169. }    // InstallAppleEventHandlers
  170.  
  171.  
  172.  
  173. #pragma segment Core
  174.  
  175. pascal OSErr HandleOpenApplication( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon )
  176. {
  177. #ifdef __MWERKS__
  178.     #pragma unused (theAppleEvent, reply, refcon )
  179. #endif
  180.  
  181.     return noErr;
  182. }
  183.  
  184.  
  185.  
  186. pascal OSErr HandleQuitApplication( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon )
  187. {
  188. #ifdef __MWERKS__
  189.     #pragma unused (theAppleEvent, reply, refcon )
  190. #endif
  191.  
  192.     OSErr    err;
  193.  
  194.     if ( gSoundChannel )
  195.     {
  196.         err = SndDisposeChannel( gSoundChannel, true );
  197.         gSoundChannel = NULL;
  198.     }
  199.  
  200.     gQuit = true;
  201.     return noErr;
  202. }
  203.  
  204.  
  205.  
  206. pascal OSErr HandleOpenDocuments( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon )
  207. {
  208. #ifdef __MWERKS__
  209.     #pragma unused (theAppleEvent, reply, refcon )
  210. #endif
  211.  
  212.     return errAEEventNotHandled;
  213. }
  214.  
  215.  
  216.  
  217. pascal OSErr HandlePrintDocuments( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon )
  218. {
  219. #ifdef __MWERKS__
  220.     #pragma unused (theAppleEvent, reply, refcon )
  221. #endif
  222.  
  223.     return errAEEventNotHandled;
  224. }
  225.  
  226.  
  227. pascal OSErr HandleFileAdded( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon )
  228. {
  229. #ifdef __MWERKS__
  230.     #pragma unused ( reply, refcon )
  231. #endif
  232.  
  233.     AEDesc        aDesc = { typeNull, NULL };
  234.     OSErr        err;
  235.     
  236.     err = AEGetParamDesc( theAppleEvent, keyDirectObject, typeWildCard, &aDesc );
  237.     if ( noErr != err) goto done;
  238.  
  239.     DisplayChange( &aDesc, kAddedStr );
  240.  
  241. done:
  242.     AEDisposeDesc( &aDesc );
  243.  
  244.     return err;
  245. }
  246.  
  247.  
  248. pascal OSErr HandleFileRemoved( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon )
  249. {
  250. #ifdef __MWERKS__
  251.     #pragma unused ( reply, refcon )
  252. #endif
  253.  
  254.     AEDesc        aDesc = { typeNull, NULL };
  255.     OSErr        err;
  256.     
  257.     err = AEGetParamDesc( theAppleEvent, keyDirectObject, typeWildCard, &aDesc );
  258.     if ( noErr != err) goto done;
  259.  
  260.     DisplayChange( &aDesc, kRemovedStr );
  261.  
  262. done:
  263.     AEDisposeDesc( &aDesc );
  264.  
  265.     return err;
  266. }
  267.  
  268.  
  269. pascal OSErr HandleFileModified( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon )
  270. {
  271. #ifdef __MWERKS__
  272.     #pragma unused ( reply, refcon )
  273. #endif
  274.  
  275.     AEDesc        aDesc = { typeNull, NULL };
  276.     OSErr        err;
  277.     
  278.     err = AEGetParamDesc( theAppleEvent, keyDirectObject, typeWildCard, &aDesc );
  279.     if ( noErr != err) goto done;
  280.  
  281.     DisplayChange( &aDesc, kModifiedStr );
  282.  
  283. done:
  284.     AEDisposeDesc( &aDesc );
  285.  
  286.     return err;
  287. }
  288.  
  289.  
  290. // AppleScript will send this type of event if you structure your call like a subroutine.
  291. // This way you can accept the events without AppleScript checking out your terminology
  292. // through the 'aete' resource.
  293.  
  294. pascal OSErr HandleASSubroutine( AppleEvent *theAppleEvent, AppleEvent *reply, long refcon )
  295. {
  296. #ifdef __MWERKS__
  297.     #pragma unused ( reply, refcon )
  298. #endif
  299.  
  300.     Str255        subroutineStr;
  301.     DescType    typeCode;
  302.     Size        actualSize;
  303.     AEDesc        aDesc = { typeNull, NULL };
  304.     OSErr        err;
  305.     
  306.     
  307.     err = AEGetParamPtr( theAppleEvent, keyASSubroutineName, typeChar,
  308.                                     &typeCode, &subroutineStr[1], 255, &actualSize );
  309.     if ( noErr != err ) goto done;
  310.     subroutineStr[0] = actualSize;
  311.     
  312.     err = AEGetParamDesc( theAppleEvent, keyDirectObject, typeWildCard, &aDesc );
  313.     if ( noErr != err ) goto done;
  314.     
  315.                 // Check we've read the resources in
  316.     if ( ! gAddedSubroutineName[0] )
  317.         GetIndString( gAddedSubroutineName, SubroutineSTRs, kAddedSub );
  318.  
  319.     if ( ! gRemovedSubroutineName[0] )
  320.         GetIndString( gRemovedSubroutineName, SubroutineSTRs, kRemovedSub );
  321.  
  322.     if ( ! gModifiedSubroutineName[0] )
  323.         GetIndString( gModifiedSubroutineName, SubroutineSTRs, kModifiedSub );
  324.  
  325.     if ( EqualString( subroutineStr, gAddedSubroutineName , false, false ))
  326.         DisplayChange( &aDesc, kAddedStr );
  327.     else if ( EqualString( subroutineStr, gRemovedSubroutineName , false, false ))
  328.         DisplayChange( &aDesc, kRemovedStr );
  329.     else if ( EqualString( subroutineStr, gModifiedSubroutineName , false, false ))
  330.         DisplayChange( &aDesc, kModifiedStr );
  331.  
  332. done:
  333.     AEDisposeDesc( &aDesc );
  334.  
  335.     return err;
  336. }
  337.  
  338.  
  339. // This routine takes care of lists
  340.  
  341. void    DisplayChange( AEDesc* theDesc, short theChange )
  342. {
  343.     AEDesc        aDesc = { typeNull, NULL };
  344.     long        aCount,
  345.                 anIndex;
  346.     AEKeyword    anAEKeyword;
  347.     OSErr        err;
  348.  
  349.     switch ( theDesc->descriptorType )
  350.     {
  351.         case typeAEList:        // Handle lists
  352.             err = AECountItems( theDesc, &aCount );
  353.             if ( noErr != err ) goto done;
  354.             
  355.             for (anIndex = 1; anIndex <= aCount; anIndex++ )
  356.             {
  357.                 err = AEGetNthDesc( theDesc, anIndex, typeWildCard, &anAEKeyword, &aDesc );
  358.                 if ( noErr != err ) goto done;
  359.                 
  360.                 DisplayChange( &aDesc, theChange );
  361.             
  362.                 (void)AEDisposeDesc( &aDesc );
  363.             }
  364.             break;
  365.             
  366.         default:
  367.             DisplayChangeDesc( theDesc, theChange );
  368.     }
  369.     
  370. done:
  371.     (void)AEDisposeDesc( &aDesc );
  372. }
  373.  
  374.  
  375. // Add the change to our list and notify user of change.
  376.  
  377. void    DisplayChangeDesc( AEDesc* theDesc, short theChange )
  378. {
  379.     Str255            displayStr,
  380.                     tempStr;
  381.     AEDesc            anFSSpecDesc = { typeNull, NULL };
  382.     FSSpec            anFSSpec;
  383.     Boolean            fDirectory;
  384.     unsigned long    now;
  385.     OSErr            err;
  386.     
  387.     err = AECoerceDesc( theDesc, typeFSS, &anFSSpecDesc );
  388.     if ( noErr != err ) goto done;
  389.     
  390.     err = GetDescriptorData( &anFSSpecDesc, (Ptr)&anFSSpec, sizeof( anFSSpec ) );
  391.     if ( noErr != err ) goto done;
  392.     
  393.     err = FSSpecIsDirectory( &anFSSpec, &fDirectory);
  394.     if ( noErr != err ) goto done;
  395.  
  396.     displayStr[0] = 0;    // Empty the string
  397.     
  398.     if ( ! fDirectory )        // If it isn't a directory then add 
  399.     {                        // the directory name before it.
  400.         err = GetParentDirectoryName( &anFSSpec, tempStr );
  401.         if ( noErr != err ) goto done;
  402.         AppendPStr( tempStr, displayStr );
  403.         AppendPStr( "\p:", displayStr );
  404.     }
  405.     
  406.     AppendPStr( anFSSpec.name, displayStr );    // Add the folder/file name
  407.     if ( fDirectory )
  408.         AppendPStr( "\p:", displayStr );        // If a directory show by sticking colon after
  409.  
  410.     GetIndString( tempStr, ChangeSTRs, theChange );
  411.     AppendPStr( "\p\t", displayStr );            // Add a tab
  412.     AppendPStr( tempStr, displayStr );            // Add Added/Removed/Modified
  413.     
  414.     GetDateTime( &now );
  415.     TimeString( now, false, tempStr, NULL );
  416.     AppendPStr( "\p\t", displayStr );            // Add a tab
  417.     AppendPStr( tempStr, displayStr );            // Add Time
  418.     
  419.     DateString( now, abbrevDate, tempStr, NULL );
  420.     AppendPStr( "\p\t", displayStr );            // Add a tab
  421.     AppendPStr( tempStr, displayStr );            // Add Date
  422.     
  423.     AddToListContent( displayStr );
  424.     
  425.     Notify( true, NotificationIcon, NULL );
  426.     
  427. done:
  428.     AEDisposeDesc( &anFSSpecDesc );
  429. }
  430.  
  431.  
  432. // Just a pascal string concatenation routine.
  433. // Doesn't check for 255 character limit.
  434.  
  435. void    AppendPStr( StringPtr sourceStr, StringPtr destStr )
  436. {
  437.     BlockMoveData( &sourceStr[1], &destStr[1] + destStr[0], sourceStr[0] );
  438.     destStr[0] += sourceStr[0];
  439. }
  440.  
  441.  
  442. // Get the data out of the data handle of the descriptor.
  443.  
  444. OSErr    GetDescriptorData( const AEDesc* theDesc, Ptr destPtr, Size maxSize )
  445. {
  446.     Size    copySize;
  447.     OSErr    err = noErr;
  448.     
  449.     if ( typeNull == theDesc->descriptorType || ! theDesc->dataHandle )
  450.         return( errAENotAEDesc );
  451.  
  452.     copySize = GetHandleSize( (Handle)theDesc->dataHandle );
  453.     if ( copySize <= maxSize )
  454.     {
  455.         HLock( (Handle)theDesc->dataHandle );
  456.         BlockMoveData( *theDesc->dataHandle, destPtr, copySize );
  457.         HUnlock( (Handle)theDesc->dataHandle );
  458.     }
  459.     else
  460.         err = errAECorruptData;
  461.     
  462.     return err;
  463. } // GetDescriptorData
  464.  
  465.  
  466. // Check to see if FSSpec is for a directory.
  467.  
  468. OSErr    FSSpecIsDirectory( FSSpec* theSpec, Boolean* theResult )
  469. {
  470.     CInfoPBRec         aPB;
  471.     OSErr             err;
  472.  
  473.     aPB.dirInfo.ioNamePtr = theSpec->name;
  474.     aPB.dirInfo.ioVRefNum = theSpec->vRefNum;
  475.     aPB.dirInfo.ioDrDirID = theSpec->parID;
  476.     aPB.dirInfo.ioFDirIndex = 0;    // Use ioNamePtr and ioDirID
  477.     aPB.dirInfo.ioACUser = 0;        // Clear it before calling GetCatInfo
  478.     err = PBGetCatInfo( &aPB, false );
  479.     
  480.     if ( noErr == err )
  481.         *theResult = ( aPB.dirInfo.ioFlAttrib & ioDirMask );
  482.  
  483.     return err;
  484. }
  485.  
  486.  
  487. // Get parent directory name for an FSSpec.
  488.  
  489. OSErr    GetParentDirectoryName( FSSpec* theSpec, StringPtr theName )
  490. {
  491.     CInfoPBRec         aPB;
  492.     OSErr             err;
  493.  
  494.     aPB.dirInfo.ioNamePtr = theName;
  495.     aPB.dirInfo.ioVRefNum = theSpec->vRefNum;
  496.     aPB.dirInfo.ioDrDirID = theSpec->parID;
  497.     aPB.dirInfo.ioFDirIndex = -1;    // Get info about the directory
  498.     aPB.dirInfo.ioACUser = 0;    // Clear it before calling GetCatInfo
  499.     err = PBGetCatInfo( &aPB, false );
  500.  
  501.     return err;
  502. }
  503.  
  504.  
  505. // Call this once during application initialization
  506.  
  507. void    InitNotification( void )
  508. {
  509.     OSErr    err;
  510.  
  511.     gRemoveNotification = false;
  512.     GetDateTime( (unsigned long *)&qd.randSeed );
  513.     gNumberSounds = Count1Resources( soundListRsrc );
  514.     gSoundChannel = NULL;
  515.     err = SndNewChannel( &gSoundChannel, 0, 0, NULL );
  516. }
  517.  
  518.  
  519. // This routine checks whether or not the notification
  520. // is already displayed. If it isn't then it puts up
  521. // a notification.
  522.  
  523. OSErr    Notify( Boolean fSound, short iconID, StringPtr message )
  524. {
  525.     Handle        sndHandle;
  526.     OSErr       err = noErr;
  527.     
  528.     fSound = ( fSound && ( gNumberSounds > 0 ) );
  529.     
  530.     if ( gRemoveNotification && fSound)
  531.     {                            // We'll still play the sounds because I like it.
  532.                                 // Note that this may drive the user crazy.
  533.         sndHandle = Get1IndResource( soundListRsrc, ( PositiveRandom( ) % gNumberSounds ) + 1 );
  534.         HNoPurge( sndHandle );
  535.         err = SndPlay( gSoundChannel, (SndListHandle)sndHandle, true );
  536.     }
  537.     else
  538.         err = InstallNotification( true, iconID, message );
  539.         
  540.     return err;
  541. }
  542.  
  543.  
  544. OSErr    InstallNotification( Boolean fSound, short iconID, StringPtr message )
  545. {
  546.     Handle        anIconSuite;
  547.     Handle        ics8Handle,
  548.                 ics4Handle,
  549.                 icsBWHandle;
  550.     Handle        sndHandle;
  551.     OSErr       err;
  552.  
  553.     gNotificationPtr = (MyNotificationPtr)NewPtrClear( sizeof( MyNotificationRecord ) );
  554.     err = MemError( );
  555.     if (noErr != err || ! gNotificationPtr ) goto done;
  556.  
  557.     gNotificationPtr->notification.qType = nmType;
  558.     gNotificationPtr->notification.nmMark = 1;        // Put a mark next to our application
  559.                                                     // in the application menu.
  560.     if ( iconID )
  561.     {
  562.         err = NewIconSuite(&anIconSuite);
  563.         if (noErr != err ) goto done;
  564.         
  565.         ics8Handle = Get1Resource( kSmall8BitData, NotificationIcon );
  566.         HNoPurge( ics8Handle );
  567.         err = AddIconToSuite( ics8Handle, anIconSuite, kSmall8BitData );
  568.         if (noErr != err ) goto done;
  569.     
  570.         ics4Handle = Get1Resource( kSmall4BitData, NotificationIcon );
  571.         HNoPurge( ics4Handle );
  572.         err = AddIconToSuite( ics4Handle, anIconSuite, kSmall4BitData );
  573.         if (noErr != err ) goto done;
  574.     
  575.         icsBWHandle = Get1Resource( kSmall1BitMask, NotificationIcon );
  576.         HNoPurge( icsBWHandle );
  577.         err = AddIconToSuite( icsBWHandle, anIconSuite, kSmall1BitMask );
  578.         if (noErr != err ) goto done;
  579.     
  580.         gNotificationPtr->notification.nmIcon = anIconSuite;
  581.     }
  582.     else
  583.         gNotificationPtr->notification.nmIcon = NULL;
  584.  
  585.         // handle to sound record
  586.     if ( fSound )
  587.     {
  588.         sndHandle = Get1IndResource( soundListRsrc, ( PositiveRandom( ) % gNumberSounds ) + 1 );
  589.         HNoPurge( sndHandle );
  590.         gNotificationPtr->notification.nmSound = sndHandle;
  591.     }
  592.     else
  593.         gNotificationPtr->notification.nmSound = NULL;
  594.  
  595.         // string to appear in alert
  596.     if ( message )    // Send NULL StringPtr if no alert wanted
  597.     {
  598.         BlockMoveData( message, gNotificationPtr->notificationString, message[0] + 1 );
  599.         gNotificationPtr->notification.nmStr = gNotificationPtr->notificationString;
  600.     }
  601.     else
  602.         gNotificationPtr->notification.nmStr = NULL;
  603.         
  604.         // pointer to response routine
  605.     gNotificationPtr->notification.nmResp = NULL;    // gMyNMProcPtr;
  606.     gNotificationPtr->notification.nmRefCon = 0;    // SetCurrentA5( );    // Copy current A5
  607.  
  608.     err = NMInstall( (NMRecPtr)gNotificationPtr );
  609.     if ( noErr == err )
  610.         gRemoveNotification = true;
  611.  
  612. done:
  613.     if ( noErr != err )        // If there was an error then clean up the memory
  614.     {
  615.         if ( gNotificationPtr->notification.nmIcon )
  616.             err = DisposeIconSuite( gNotificationPtr->notification.nmIcon, false );
  617.         
  618.         DisposPtr( (Ptr)gNotificationPtr );
  619.         gNotificationPtr = NULL;
  620.     }
  621.  
  622.     return err;
  623. }
  624.  
  625.  
  626. // If there is a notification running then this routine removes it
  627. // and disposes of the associated memory.
  628.  
  629. OSErr    RemoveNotification( void )
  630. {
  631.     OSErr   err = noErr;
  632.     
  633.     if ( gRemoveNotification )
  634.     {
  635.         err = NMRemove( (NMRecPtr)gNotificationPtr );
  636.  
  637.         if ( gNotificationPtr->notification.nmIcon )
  638.             err = DisposeIconSuite( gNotificationPtr->notification.nmIcon, false );
  639.  
  640.         DisposPtr( (Ptr)gNotificationPtr );
  641.         gNotificationPtr = NULL;
  642.         
  643.         gRemoveNotification = false;        // Reset the flag
  644.     }
  645.  
  646.     return err;
  647. } // RemoveNotification
  648.  
  649.  
  650. short    PositiveRandom( void )
  651. {
  652.     short    aRandom = Random( );
  653.     
  654.     if ( aRandom >= 0 )
  655.         return aRandom;
  656.     else
  657.         return aRandom * -1;
  658. }